package cn.vendai.com.controller;

import cn.vendcommon.com.entity.Result;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.loader.FileSystemDocumentLoader;
import dev.langchain4j.data.document.parser.apache.pdfbox.ApachePdfBoxDocumentParser;
import dev.langchain4j.data.document.parser.apache.poi.ApachePoiDocumentParser;
import dev.langchain4j.data.document.parser.apache.tika.ApacheTikaDocumentParser;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
import io.minio.GetPresignedObjectUrlArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.http.Method;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@RestController
@RequestMapping("/knowledge")
public class KnowledgeController {

    @Autowired
    private MinioClient minioClient;

    @Autowired
    private EmbeddingStore<TextSegment> embeddingStore;

    @Autowired
    private EmbeddingModel embeddingModel;

    @Value("${minio.bucket}")
    private String bucketName;

    @Value("${minio.expiration_time}")
    private int expiration_time;

    /**
     * 上传知识库文档，并向量化存入数据库
     */
    @PostMapping("/upload")
    public Result<String> uploadKnowledge(@RequestParam("file") MultipartFile file) throws Exception {
        // 上传到 MinIO
        String objectName = "docs/" + System.currentTimeMillis() + "_" + file.getOriginalFilename();

        minioClient.putObject(
                PutObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .stream(file.getInputStream(), file.getSize(), -1)
                        .contentType(file.getContentType())
                        .build()
        );

        log.info("文件已上传到 MinIO，objectName={}", objectName);

        // 需要加载文档 -> 先落地到临时文件（因为 Langchain4j 的 loader 目前是基于文件路径的）
        File tempFile = File.createTempFile("doc_", "_" + file.getOriginalFilename());
        try (FileOutputStream fos = new FileOutputStream(tempFile)) {
            fos.write(file.getBytes());
        }

        // 根据文件后缀选择解析器
        String filename = file.getOriginalFilename();
        Document document;
        if (filename != null) {
            if (filename.endsWith(".pdf")) {
                // 使用 PDF 解析器
                document = FileSystemDocumentLoader.loadDocument(
                        tempFile.getAbsolutePath(),
                        new ApachePdfBoxDocumentParser()
                );
            } else if (filename.endsWith(".doc") || filename.endsWith(".docx")) {
                // 使用 Word 解析器
                document = FileSystemDocumentLoader.loadDocument(
                        tempFile.getAbsolutePath(),
                        new ApachePoiDocumentParser()
                );
            } else {
                // 其他文件类型用 Tika
                document = FileSystemDocumentLoader.loadDocument(
                        tempFile.getAbsolutePath(),
                        new ApacheTikaDocumentParser()
                );
            }
        } else {
            throw new RuntimeException("文件名为空，无法识别类型！");
        }

        // 向量化存储
        EmbeddingStoreIngestor
                .builder()
                .embeddingStore(embeddingStore)
                .embeddingModel(embeddingModel)
                .build()
                .ingest(document);

        log.info("文件向量化并入库成功：{}", file.getOriginalFilename());

        // 删除临时文件
        tempFile.delete();

        // 生成预签名 URL（有效期 1 小时）
        String presignedUrl = minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                        .method(Method.GET)
                        .bucket(bucketName)
                        .object(objectName)
                        .expiry(expiration_time) // 1小时
                        .build()
        );
        // 返回预签名URL
        return Result.success(presignedUrl);
    }
}
